/******************************************************************************* * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ant.internal.ui.preferences; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.ant.core.Property; import org.eclipse.ant.internal.core.IAntCoreConstants; import org.eclipse.ant.internal.ui.AntUIPlugin; import org.eclipse.ant.internal.ui.AntUtil; import org.eclipse.ant.internal.ui.ColumnSorter; import org.eclipse.ant.internal.ui.IAntUIConstants; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ColumnLayoutData; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import com.ibm.icu.text.MessageFormat; public class AntPropertiesBlock { /** * Constant representing the id of the settings for the property table column widths * * @since 3.5 */ private static final String PROPERTY_COLUMN_WIDTH = "ant.properties.block.property.columnWidth"; //$NON-NLS-1$ /** * Constant representing the id of the settings for the property table sort column * * @since 3.5 */ private static final String PROPERTY_SORT_COLUMN = "ant.properties.block.property.sortColumn"; //$NON-NLS-1$ /** * Constant representing the id of the settings for the property table sort direction * * @since 3.5 */ private static final String PROPERTY_SORT_DIRECTION = "ant.properties.block.property.sortDirection"; //$NON-NLS-1$ private IAntBlockContainer container; private Button editButton; private Button removeButton; private Button addButton; private Button addFileButton; private Button addExternalFileButton; private Button removeFileButton; private TableViewer propertyTableViewer; private TableViewer fileTableViewer; private final AntObjectLabelProvider labelProvider = new AntObjectLabelProvider(); private IDialogSettings dialogSettings; private boolean tablesEnabled = true; private final String[] fTableColumnHeaders = { AntPreferencesMessages.AntPropertiesBlock_0, AntPreferencesMessages.AntPropertiesBlock_5, AntPreferencesMessages.AntPropertiesBlock_6 }; private final ColumnLayoutData[] fTableColumnLayouts = { new ColumnWeightData(30),// , 190, true), new ColumnWeightData(40),// , 190, true), new ColumnWeightData(30) // , 190, true) }; /** * Button listener that delegates for widget selection events. */ private SelectionAdapter buttonListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { if (event.widget == addButton) { addProperty(); } else if (event.widget == editButton) { edit(); } else if (event.widget == removeButton) { remove(propertyTableViewer); } else if (event.widget == addFileButton) { addPropertyFile(); } else if (event.widget == addExternalFileButton) { addExternalPropertyFile(); } else if (event.widget == removeFileButton) { remove(fileTableViewer); } } }; /** * Key listener that delegates for key pressed events. */ private KeyAdapter keyListener = new KeyAdapter() { @Override public void keyPressed(KeyEvent event) { if (event.getSource() == propertyTableViewer) { if (removeButton.isEnabled() && event.character == SWT.DEL && event.stateMask == 0) { remove(propertyTableViewer); } } else if (event.getSource() == fileTableViewer) { if (removeFileButton.isEnabled() && event.character == SWT.DEL && event.stateMask == 0) { remove(fileTableViewer); } } } }; /** * Selection changed listener that delegates selection events. */ private ISelectionChangedListener tableListener = new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { if (tablesEnabled) { if (event.getSource() == propertyTableViewer) { propertyTableSelectionChanged((IStructuredSelection) event.getSelection()); } else if (event.getSource() == fileTableViewer) { fileTableSelectionChanged((IStructuredSelection) event.getSelection()); } } } }; public AntPropertiesBlock(IAntBlockContainer container) { this.container = container; } private void addPropertyFile() { String title = AntPreferencesMessages.AntPropertiesFileSelectionDialog_12; String message = AntPreferencesMessages.AntPropertiesFileSelectionDialog_13; String filterExtension = "properties"; //$NON-NLS-1$ String filterMessage = AntPreferencesMessages.AntPropertiesFileSelectionDialog_14; Object[] existingFiles = getPropertyFiles(); List<IFile> propFiles = new ArrayList<>(existingFiles.length); for (int j = 0; j < existingFiles.length; j++) { String file = (String) existingFiles[j]; try { propFiles.add(AntUtil.getFileForLocation(VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(file), null)); } catch (CoreException e) { AntUIPlugin.log(e.getStatus()); } } FileSelectionDialog dialog = new FileSelectionDialog(propertyTableViewer.getControl().getShell(), propFiles, title, message, filterExtension, filterMessage); if (dialog.open() == Window.OK) { Object[] elements = dialog.getResult(); for (int i = 0; i < elements.length; i++) { IFile file = (IFile) elements[i]; String varExpression = VariablesPlugin.getDefault().getStringVariableManager().generateVariableExpression("workspace_loc", file.getFullPath().toString()); //$NON-NLS-1$ ((AntContentProvider) fileTableViewer.getContentProvider()).add(varExpression); } container.update(); } } public void createControl(Composite top, String propertyLabel, String propertyFileLabel) { Font font = top.getFont(); dialogSettings = AntUIPlugin.getDefault().getDialogSettings(); Label label = new Label(top, SWT.NONE); GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); gd.horizontalSpan = 2; label.setLayoutData(gd); label.setFont(font); label.setText(propertyLabel); int idx = 0; int direction = SWT.DOWN; try { idx = dialogSettings.getInt(PROPERTY_SORT_COLUMN); direction = dialogSettings.getInt(PROPERTY_SORT_DIRECTION); } catch (NumberFormatException e) { // do nothing } propertyTableViewer = createTableViewer(top, true, false, idx, direction); propertyTableViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { if (!event.getSelection().isEmpty() && editButton.isEnabled()) { edit(); } } }); propertyTableViewer.getTable().addKeyListener(keyListener); createButtonGroup(top); label = new Label(top, SWT.NONE); gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); gd.horizontalSpan = 2; label.setLayoutData(gd); label.setFont(font); label.setText(propertyFileLabel); fileTableViewer = createTableViewer(top, false, true, 0, SWT.DOWN); fileTableViewer.getTable().addKeyListener(keyListener); createButtonGroup(top); } /** * Creates the group which will contain the buttons. */ private void createButtonGroup(Composite top) { Composite buttonGroup = new Composite(top, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; buttonGroup.setLayout(layout); buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL)); buttonGroup.setFont(top.getFont()); addButtonsToButtonGroup(buttonGroup); } /** * Creates and returns a configured table viewer in the given parent */ private TableViewer createTableViewer(Composite parent, boolean setColumns, boolean defaultsorting, int sortcolumnidx, int sortdirection) { Table table = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER); GridData data = new GridData(GridData.FILL_BOTH); int availableRows = availableRows(parent); if (setColumns) { data.heightHint = table.getItemHeight() * (availableRows / 10); } data.widthHint = 425; table.setLayoutData(data); table.setFont(parent.getFont()); TableViewer tableViewer = new TableViewer(table); tableViewer.setContentProvider(new AntContentProvider(defaultsorting)); tableViewer.setLabelProvider(labelProvider); tableViewer.addSelectionChangedListener(tableListener); if (setColumns) { TableLayout tableLayout = new TableLayout(); table.setLayout(tableLayout); table.setHeaderVisible(true); table.setLinesVisible(true); ColumnSorter sorter = null; for (int i = 0; i < fTableColumnHeaders.length; i++) { tableLayout.addColumnData(fTableColumnLayouts[i]); TableColumn column = new TableColumn(table, SWT.NONE, i); column.setResizable(fTableColumnLayouts[i].resizable); column.setText(fTableColumnHeaders[i]); sorter = new ColumnSorter(tableViewer, column) { @Override public String getCompareText(Object obj, int columnindex) { return AntPropertiesBlock.this.labelProvider.getColumnText(obj, columnindex); } }; if (i == sortcolumnidx) { sorter.setDirection(sortdirection); } } } return tableViewer; } /** * Used to persist any settings for the block that the user has set * * @since 3.5 */ public void saveSettings() { if (propertyTableViewer != null) { saveColumnSettings(); } } /** * Persist table settings into the give dialog store. * * @since 3.5 */ private void saveColumnSettings() { Table table = this.propertyTableViewer.getTable(); int columnCount = table.getColumnCount(); for (int i = 0; i < columnCount; i++) { dialogSettings.put(PROPERTY_COLUMN_WIDTH + i, table.getColumn(i).getWidth()); } TableColumn column = table.getSortColumn(); if (column != null) { dialogSettings.put(PROPERTY_SORT_COLUMN, table.indexOf(column)); dialogSettings.put(PROPERTY_SORT_DIRECTION, table.getSortDirection()); } } /** * Restore table settings from the given dialog store. * * @since 3.5 */ private void restoreColumnSettings() { if (this.propertyTableViewer == null) { return; } restoreColumnWidths(); } /** * Restores the column widths from dialog settings * * @since 3.5 */ private void restoreColumnWidths() { Table table = this.propertyTableViewer.getTable(); int columnCount = table.getColumnCount(); for (int i = 0; i < columnCount; i++) { int width = -1; try { width = dialogSettings.getInt(PROPERTY_COLUMN_WIDTH + i); } catch (NumberFormatException e) { // do nothing } if ((width <= 0) || (i == table.getColumnCount() - 1)) { table.getColumn(i).pack(); } else { table.getColumn(i).setWidth(width); } } } /** * Return the number of rows available in the current display using the current font. * * @param parent * The Composite whose Font will be queried. * @return The result of the display size divided by the font size. */ private int availableRows(Composite parent) { int fontHeight = (parent.getFont().getFontData())[0].getHeight(); int displayHeight = parent.getDisplay().getClientArea().height; return displayHeight / fontHeight; } /* * (non-Javadoc) Method declared on AntPage. */ protected void addButtonsToButtonGroup(Composite parent) { if (editButton == null) { addButton = createPushButton(parent, AntPreferencesMessages.AntPropertiesBlock_1); editButton = createPushButton(parent, AntPreferencesMessages.AntPropertiesBlock_2); removeButton = createPushButton(parent, AntPreferencesMessages.AntPropertiesBlock_3); } else { addFileButton = createPushButton(parent, AntPreferencesMessages.AntPropertiesBlock_4); addExternalFileButton = createPushButton(parent, AntPreferencesMessages.AntPropertiesBlock_14); removeFileButton = createPushButton(parent, AntPreferencesMessages.AntPropertiesBlock_removeFileButton); } } /** * Creates and returns a configured button in the given composite with the given label. Widget selection call-backs for the returned button will * be processed by the <code>buttonListener</code> */ private Button createPushButton(Composite parent, String label) { Button button = container.createPushButton(parent, label); button.addSelectionListener(buttonListener); GridData gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL); button.setLayoutData(gridData); return button; } /** * Allows the user to enter external property files */ private void addExternalPropertyFile() { String lastUsedPath; lastUsedPath = dialogSettings.get(IAntUIConstants.DIALOGSTORE_LASTEXTFILE); if (lastUsedPath == null) { lastUsedPath = IAntCoreConstants.EMPTY_STRING; } FileDialog dialog = new FileDialog(fileTableViewer.getControl().getShell(), SWT.MULTI); dialog.setFilterExtensions(new String[] { "*.properties", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$; dialog.setFilterPath(lastUsedPath); String result = dialog.open(); if (result == null) { return; } IPath filterPath = new Path(dialog.getFilterPath()); String[] results = dialog.getFileNames(); for (int i = 0; i < results.length; i++) { String fileName = results[i]; IPath path = filterPath.append(fileName).makeAbsolute(); ((AntContentProvider) fileTableViewer.getContentProvider()).add(path.toOSString()); } dialogSettings.put(IAntUIConstants.DIALOGSTORE_LASTEXTFILE, filterPath.toOSString()); container.update(); } private void remove(TableViewer viewer) { AntContentProvider antContentProvider = (AntContentProvider) viewer.getContentProvider(); IStructuredSelection sel = (IStructuredSelection) viewer.getSelection(); antContentProvider.remove(sel); container.update(); } /** * Allows the user to enter a user property */ private void addProperty() { String title = AntPreferencesMessages.AntPropertiesBlock_Add_Property_2; AddPropertyDialog dialog = new AddPropertyDialog(propertyTableViewer.getControl().getShell(), title, new String[] { IAntCoreConstants.EMPTY_STRING, IAntCoreConstants.EMPTY_STRING }); if (dialog.open() == Window.CANCEL) { return; } String[] pair = dialog.getNameValuePair(); String name = pair[0]; if (!overwrite(name)) { return; } Property prop = new Property(); prop.setName(name); prop.setValue(pair[1]); ((AntContentProvider) propertyTableViewer.getContentProvider()).add(prop); container.update(); } private void edit() { IStructuredSelection selection = (IStructuredSelection) propertyTableViewer.getSelection(); Property prop = (Property) selection.getFirstElement(); String originalName = prop.getName(); String title = AntPreferencesMessages.AntPropertiesBlock_Edit_User_Property_5; AddPropertyDialog dialog = new AddPropertyDialog(propertyTableViewer.getControl().getShell(), title, new String[] { prop.getName(), prop.getValue(false) }); if (dialog.open() == Window.CANCEL) { return; } String[] pair = dialog.getNameValuePair(); String name = pair[0]; if (!name.equals(originalName)) { if (!overwrite(name)) { return; } } prop.setName(name); prop.setValue(pair[1]); // trigger a resort propertyTableViewer.refresh(); container.update(); } private boolean overwrite(String name) { Object[] properties = getProperties(); for (int i = 0; i < properties.length; i++) { Property property = (Property) properties[i]; String propertyName = property.getName(); if (propertyName.equals(name)) { if (property.isDefault()) { MessageDialog.openError(propertyTableViewer.getControl().getShell(), AntPreferencesMessages.AntPropertiesBlock_17, MessageFormat.format(AntPreferencesMessages.AntPropertiesBlock_18, new Object[] { propertyName, property.getPluginLabel() })); return false; } boolean overWrite = MessageDialog.openQuestion(propertyTableViewer.getControl().getShell(), AntPreferencesMessages.AntPropertiesBlock_15, MessageFormat.format(AntPreferencesMessages.AntPropertiesBlock_16, new Object[] { name })); if (!overWrite) { return false; } ((AntContentProvider) propertyTableViewer.getContentProvider()).remove(property); break; } } return true; } /** * Handles selection changes in the Property file table viewer. */ private void fileTableSelectionChanged(IStructuredSelection newSelection) { removeFileButton.setEnabled(newSelection.size() > 0); } /** * Handles selection changes in the Property table viewer. */ private void propertyTableSelectionChanged(IStructuredSelection newSelection) { int size = newSelection.size(); boolean enabled = true; Iterator<Object> itr = newSelection.iterator(); while (itr.hasNext()) { Object element = itr.next(); if (element instanceof Property) { Property property = (Property) element; if (property.isDefault()) { enabled = false; break; } } } editButton.setEnabled(enabled && size == 1); removeButton.setEnabled(enabled && size > 0); } public void populatePropertyViewer(Map<String, String> properties) { if (properties == null) { propertyTableViewer.setInput(new Property[0]); return; } Property[] result = new Property[properties.size()]; Iterator<Map.Entry<String, String>> entries = properties.entrySet().iterator(); int i = 0; while (entries.hasNext()) { Entry<String, String> element = entries.next(); Property property = new Property(); property.setName(element.getKey()); property.setValue(element.getValue()); result[i] = property; i++; } propertyTableViewer.setInput(result); restoreColumnSettings(); } public void setPropertiesInput(Property[] properties) { propertyTableViewer.setInput(properties); } public void setPropertyFilesInput(String[] files) { fileTableViewer.setInput(files); } public void update() { propertyTableSelectionChanged((IStructuredSelection) propertyTableViewer.getSelection()); fileTableSelectionChanged((IStructuredSelection) fileTableViewer.getSelection()); } public Object[] getProperties() { return ((AntContentProvider) propertyTableViewer.getContentProvider()).getElements(null); } public Object[] getPropertyFiles() { return ((AntContentProvider) fileTableViewer.getContentProvider()).getElements(null); } public void setEnabled(boolean enable) { setTablesEnabled(enable); addButton.setEnabled(enable); addExternalFileButton.setEnabled(enable); addFileButton.setEnabled(enable); editButton.setEnabled(enable); removeButton.setEnabled(enable); removeFileButton.setEnabled(enable); if (enable) { propertyTableViewer.setSelection(propertyTableViewer.getSelection()); fileTableViewer.setSelection(fileTableViewer.getSelection()); } } public void setTablesEnabled(boolean tablesEnabled) { this.tablesEnabled = tablesEnabled; } }